﻿using System.Diagnostics;

namespace DimensionsHelper.Serialization.CommandLine;


/// <summary>
/// 存储控制台参数值信息。
/// 控制台参数应当满足格式：ArgumentName[=ArgumentValue]
/// 其中，参数名不可忽略，参数值可以忽略。
/// </summary>
[DebuggerDisplay("{Name} {Kind}")]
public class ArgumentPropertyInfo
{

    public ArgumentPropertyInfo(ArgumentKind argumentKind, string argName, Type propertyType)
    {
        Kind = argumentKind;
        Name = argName;
        PropertyType = propertyType;
        InitBasicConverter();
    }


    /// <summary>
    /// 参数类型
    /// </summary>
    public ArgumentKind Kind { get; }


    /// <summary>
    /// 控制台中的参数名
    /// </summary>
    public string Name { get; }


    /// <summary>
    /// 列表文本的元素分隔符
    /// </summary>
    public string ListSeparator { get; set; } = ";";


    /// <summary>
    /// 列表值是否允许沿用上一个有效值
    /// </summary>
    public bool CanFollow { get; set; }


    /// <summary>
    /// 设置当参数值属性的值
    /// </summary>
    public Action<object, object?>? Setter { get; set; }


    /// <summary>
    /// 获取参数对象属性值
    /// </summary>
    public Func<object, object?>? Getter { get; set; }


    /// <summary>
    /// 向列表中添加元素的回调函数，此回调的第一个参数类型应当和<see cref="Getter"/>的返回类型
    /// 以及<see cref="Setter"/>接收的第二个参数类型一致。
    /// </summary>
    public Action<object, object?>? ListAddHandler { get; set; }


    /// <summary>
    /// 将字符串值转换为对应值的转换函数。
    /// </summary>
    public Func<string?, object?>? Converter { get; set; }


    /// <summary>
    /// 属性值类型对象构造函数。
    /// </summary>
    public Func<object>? ObjectCreator { get; set; }


    /// <summary>
    /// 如果此属性是自定义类型，此参数目标对象类型
    /// </summary>
    public Func<ArgumentObject?>? PropertyObjectGetter { get; set; }


    /// <summary>
    /// 如果此属性是列表并且元素类型是对象，将元素类型参数对象设置到此属性
    /// </summary>
    public ArgumentObject? ListElementObject { get; set; }


    /// <summary>
    /// 属性类型
    /// </summary>
    public Type PropertyType { get; }



    protected static object? BooleanConverter(string? value)
    {
        // Empty string is true.
        if (string.IsNullOrEmpty(value))
        {
            return true;
        }

        if (bool.TryParse(value, out var res))
        {
            return res;
        }

        return null;
    }


    protected static object? IntegerConverter(string? value)
    {
        if (!string.IsNullOrEmpty(value) && int.TryParse(value, out var res))
        {
            return res;
        }

        return null;
    }


    protected static object? DoubleConverter(string? value)
    {
        if (!string.IsNullOrEmpty(value) && double.TryParse(value, out var res))
        {
            return res;
        }

        return null;
    }


    protected static object? FloatConverter(string? value)
    {
        if (!string.IsNullOrEmpty(value) && float.TryParse(value, out var res))
        {
            return res;
        }

        return null;
    }


    protected object? EnumConverter(string? value)
    {
        if (!PropertyType.IsEnum)
        {
            throw new Exception($"类型'{PropertyType.Name}'不是枚举类型.");
        }

        if (!string.IsNullOrEmpty(value) && Enum.TryParse(PropertyType, value, true, out var res))
        {
            return res;
        }

        return null;
    }


    private void InitBasicConverter()
    {
        if (Converter != null)
        {
            return;
        }

        if (PropertyType == typeof(int))
        {
            Converter = IntegerConverter;
        }
        else if (PropertyType == typeof(double))
        {
            Converter = DoubleConverter;
        }
        else if (PropertyType == typeof(float))
        {
            Converter = FloatConverter;
        }
        else if (PropertyType == typeof(bool))
        {
            Converter = BooleanConverter;
        }
        else if (PropertyType.IsEnum)
        {
            Converter = EnumConverter;
        }
    }

}


/// <summary>
/// 保存控制台参数中字典键值对的参数信息
/// </summary>
public class ArgumentDictionaryInfo : ArgumentPropertyInfo
{

    public ArgumentDictionaryInfo(Type dictType, ArgumentPropertyInfo key, ArgumentPropertyInfo value) :
        base(ArgumentKind.Dictionary, "", dictType)
    {
        Key = key;
        Value = value;
    }


    /// <summary>
    /// 字典关键字参数信息
    /// </summary>
    public ArgumentPropertyInfo Key { get; }


    /// <summary>
    /// 字典值参数信息
    /// </summary>
    public ArgumentPropertyInfo Value { get; }


    /// <summary>
    /// 向字典中添加键值对的回调函数。
    /// </summary>
    public Action<object, object?, object?>? DictionaryAddHandler { get; set; }

}


/// <summary>
/// 参数类型
/// </summary>
public enum ArgumentKind
{

    /// <summary>
    /// 一般的值类型属性
    /// </summary>
    Regular,

    /// <summary>
    /// 列表类型参数
    /// </summary>
    List,

    /// <summary>
    /// 字典属性
    /// </summary>
    Dictionary,

    /// <summary>
    /// 对象属性值
    /// </summary>
    Object,
}
